﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

// update et draw les scenes ici, meme systeme que les camera, SetActiveScene blablabla
namespace DARE
{
    public class CSceneMgr
    {

    #region fields

        private Dictionary<string, CScene> m_scenes = new Dictionary<string, CScene>();
        private CScene m_activeScene = null;
        private int m_activeSceneIndex = -1;

    #endregion

    #region properties

        public CScene ActiveScene
        {
            get { return m_activeScene; }
            set { SetActiveScene(value); }
        }

        public int ActiveSceneIndex
        {
            get { return m_activeSceneIndex; }
            set { SetActiveScene(value); }
        }

        public int Count
        {
            get { return m_scenes.Count; }
        }

    #endregion

    #region run

        public void Update(GameTime gameTime)
        {
            if (m_activeScene != null)
                m_activeScene.Update(gameTime);
        }

        public void Draw(GameTime gameTime)
        {
            if (m_activeScene != null)
                m_activeScene.Draw(gameTime);
        }

    #endregion

    #region methods

        /// <summary>
        /// Use to display the scene manager with all his scenes
        /// </summary>
        /// <returns>The string to display</returns>
        public override string ToString()
        {
            string strSceneMgr;

            strSceneMgr = "SceneMgr { ";
            foreach (CScene scene in m_scenes.Values)
                strSceneMgr += scene.ToString() + " ";
            strSceneMgr += "}";
            return strSceneMgr;
        }

        /// <summary>
        /// Throw an error if a scene with this name exists
        /// </summary>
        /// <param name="sceneName">Name of the scene to check</param>
        private void CheckSceneExist(string sceneName)
        {
            if (m_scenes.ContainsKey(sceneName))
                throw new Exception("scene name already exists !");
        }

        /// <summary>
        /// Create a new scene with the specified name
        /// </summary>
        /// <param name="sceneName">Name of the scene</param>
        /// <returns>The created scene</returns>
        public CScene CreateScene(string sceneName)
        {
            CScene scene = new CScene(sceneName);
            if (m_activeScene == null)
            {
                m_activeScene = scene;
                m_activeSceneIndex = 0;
            }
            return scene;
        }

        /// <summary>
        /// Register a scene
        /// </summary>
        /// <param name="scene">Scene to register</param>
        /// <returns>The registered scene</returns>
        public CScene RegisterScene(CScene scene)
        {
            CheckSceneExist(scene.Name);
            if (m_activeScene == null)
            {
                m_activeScene = scene;
                m_activeSceneIndex = 0;
            }
            m_scenes.Add(scene.Name, scene);
            return scene;
        }

        /// <summary>
        /// Return a scene by name
        /// </summary>
        /// <param name="sceneName">Name of the scene to get</param>
        /// <returns>Null if no scene with this name is found, or the scene if it exists</returns>
        public CScene GetScene(string sceneName)
        {
            if (m_scenes.ContainsKey(sceneName))
                return m_scenes[sceneName];
            return null;
        }

        public CScene GetScene(int index)
        {
            if ((index < m_scenes.Count) && (index >= 0))
                return m_scenes.ElementAt(index).Value;
            return null;
        }

        public CScene SetActiveScene(int index)
        {
            m_activeScene = GetScene(index);
            if (m_activeScene != null)
            {
                m_activeSceneIndex = index;
                SceneSettedActive(m_activeScene);
            }
            else
                m_activeSceneIndex = -1;
            return m_activeScene;
        }

        public CScene SetActiveScene(string name)
        {
            m_activeScene = GetScene(name);
            if (m_activeScene != null)
            {
                int index = 0;

                foreach (string scen in m_scenes.Keys)
                {
                    if (scen == name)
                        break;
                    index += 1;
                }
                m_activeSceneIndex = index;
            }
            else
                m_activeSceneIndex = -1;
            SceneSettedActive(m_activeScene);
            return m_activeScene;
        }

        public CScene SetActiveScene(CScene scene)
        {
            return SetActiveScene(scene.Name);
        }

        /// <summary>
        /// Change the name of a scene
        /// </summary>
        /// <param name="oldName">Name of the scene to change</param>
        /// <param name="newName">New name for the scene</param>
        /// <returns>Scene</returns>
        public CScene ChangeSceneName(string oldName, string newName)
        {
            if (!m_scenes.ContainsKey(oldName))
                throw new Exception("No scene found with name \"" + oldName + "\" !");
            CheckSceneExist(newName);
            m_scenes.Add(newName, m_scenes[oldName]);
            m_scenes.Remove(oldName);
            return m_scenes[newName];
        }

        /// <summary>
        /// Unregister a scene from the scene manager and return it
        /// </summary>
        /// <param name="sceneName">Name of the scene to unregister</param>
        /// <returns>Null if no scene with the given name was found, otherwise return the scene</returns>
        public CScene UnregisterScene(string sceneName)
        {
            if (!m_scenes.ContainsKey(sceneName))
                return null;
            CScene scene = m_scenes[sceneName];
            m_scenes.Remove(sceneName);
            if (m_activeScene.Equals(scene))
            {
                m_activeScene = null;
                m_activeSceneIndex = -1;
            }
            return scene;
        }

        /// <summary>
        /// Unregister a scene
        /// </summary>
        /// <param name="scene">Scene to unregister</param>
        /// <returns>Null if no scene was found, or the scene if success</returns>
        public CScene UnregisterScene(CScene scene)
        {
             foreach (CScene sc in m_scenes.Values)
                if (sc.Equals(scene))
                {
                    m_scenes.Remove(sc.Name);
                    if (m_activeScene.Equals(sc))
                    {
                        m_activeScene = null;
                        m_activeSceneIndex = -1;
                    }
                    return sc;
                }
            return null;
        }

        /// <summary>
        /// Unregister all scenes
        /// </summary>
        /// <returns>True if at least one scene was remove, false otherwise</returns>
        public bool UnregisterScenes()
        {
            if (m_scenes.Count == 0)
                return false;
            m_scenes.Clear();
            m_activeScene = null;
            m_activeSceneIndex = -1;
            return true;
        }

        private void SceneSettedActive(CScene _sc)
        {
            CResourceMgr.Load(_sc, true);
        }

    #endregion

    }
}
